import re,glob
from optparse import OptionParser

class LineEdit:
    def __init__(self,fname):
        self.fname = fname
        self.lines = open(fname).read().splitlines()
        self.linenum = 0
        
    def matches(self,pat):
        #print "looking for",pat
        for i,l in enumerate(self.lines):
            if re.match(pat,l):
                yield i,l
        return
        
    def setline(self,n):
        self.linenum = n
    def insert_before(self,text):
        self.lines.insert(self.linenum,text)
        self.linenum+=1
    def insert_after(self,text):
        self.lines.insert(self.linenum+1,text)
    def cont(self):
        return "\n".join(self.lines) + "\n"
    
    def curline(self):
        return self.lines[self.linenum]
    def replace_line(self,text):
        self.lines[self.linenum] = text
    def delete_line(self):
        del self.lines[self.linenum]

    def write(self):
        open(self.fname,"w").write(self.cont())
        

def assert_has_directive(files,afterlastpat, directive, directivepat = None):
    if directivepat is None:
        directivepat = directive
    for f in files:
            le = LineEdit(f)
            matches = list(le.matches(directivepat))
            #print matches
            if matches:
                print "[%s] already in %s,skipping" % (matches[0][1],f)
                continue
            matches = list(le.matches(afterlastpat))
            #print matches
            if not matches:
                matches = [(0,"")]
            
            le.setline(matches[-1][0])
            le.insert_after(directive)
            print "Writing file",f
            le.write()

def assert_include(files, include_entry):
    #e.g. include = '<d2ddebug.h>' or '"d2ddebug.h"'
    assert_has_directive(files, afterlastpat = "#include", 
        directive = "#include " + include_entry, 
        directivepat = '#include\s*["<]%s[">]' % include_entry[1:-1])

def assert_mmp_directive(files, directive):
    pre, rest = directive.split(None,1)    
    assert pre == pre.upper() # ensure LIBRARY, SYSTEMINCLUDE etc
    assert_has_directive(files, afterlastpat = pre,
                         directive = directive, 
                         directivepat = pre + r".*" + "\s+".join(rest.split()))
                         
def gettargets(args):
    """ try to get targets with mglob or normal glob """
    try:
        import mglob
    except ImportError:
        print "Hint: 'easy_install mglob' for extended wildcards."
        import glob
        return glob.glob(args[0])
    
    if not args:
        print mglob.globsyntax
        return []
    return mglob.expand(args)

def main():
    le = None
    parser = OptionParser()
    parser.add_option("-u", "--userinc", dest="userinclude",
                      help='Add user include, e.g --userinc="debug.h"', metavar="inc",
                      default=None
                      )
    parser.add_option("-s", "--sysinc", dest="systeminclude",
                      help='Add <systeminclude>, e.g --sysinc="debug.h"', metavar="inc",
                      default=None
                      )
    parser.add_option("-m", "--mmp", dest="mmpdirective",
                      help='Add directive to mmp files, e.g --mmp="LIBRARY flogger.lib"', metavar="directive",
                      default=None
                      )

    parser.add_option("-g", "--go", dest="gopattern",
                      help='Go to every line matching regex', metavar="pattern",
                      default=None
                      )
    parser.add_option("-t", "--set", dest="setcont",
                      help='Set "current" line, after --go', metavar="text",
                      default=None
                      )
    parser.add_option("-d", "--del", action = 'store_true',dest="dellines",
                      help='Delete "current" line, after --go', metavar="text",
                      default=False
                      )

                      
    (options, args) = parser.parse_args()
    targets = gettargets(args)
    if options.userinclude:
        assert_include(targets, '"%s"' % options.userinclude)
    elif options.systeminclude:
        assert_include(targets, '<%s>' % options.systeminclude)
    elif options.mmpdirective:
        assert_mmp_directive(targets, options.mmpdirective)
        
    if options.gopattern:
        for trg in targets:
            dirty = False

            le = LineEdit( trg )
          
            matches = list(le.matches( options.gopattern ))
            matches.reverse()
            print "Processing",trg,"-",len(matches),"matches."
            for m,dummy in matches:
                print "Going",m,dummy
                le.setline(m)
                if options.setcont:
                    le.replace_line( options.setcont )
                    dirty = True
                elif options.dellines:
                    le.delete_line()
                    dirty = True
        
            if dirty:
                print "Writing file..."
                le.write()
            
        

def test():
    assert_include(glob.glob("*.cpp"), '"d2ddebug.h"')


if __name__ == "__main__": main()
